package com.itheima.dubbo.mongodb.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.dubbo.config.annotation.Service;
import com.itheima.commons.model.mongo.UserLocation;
import com.itheima.commons.model.vo.UserLocationVo;
import com.itheima.dubbo.interfaces.UserLocationApi;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.GetQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class UserLocationApiImpl implements UserLocationApi {


    @Autowired
    private ElasticsearchTemplate esTemplate;

    /**
     * 这个方法什么时候执行 ??
     * <bean id=  class=  initMethod= de... />
     * 当这个Bean被Spring容器创建完后就会执行
     */
    @PostConstruct
    public void initIndex() {
        //  创建索引
        if (!esTemplate.indexExists(UserLocation.class)) {
            if (esTemplate.createIndex(UserLocation.class)) {
                //  添加映射
                esTemplate.putMapping(UserLocation.class);
            }
        }
    }

    /**
     * 上传/更新用户位置信息
     *
     * @param userId    用户id
     * @param longitude 经度
     * @param latitude  纬度
     * @param address   地址名称
     * @return
     */
    @Override
    public Boolean updateUserLocation(Long userId, Double longitude, Double latitude, String address) {
        try {
            // 先判断  当前这个用户的位置是否保存过
            GetQuery getQuery = new GetQuery();
            getQuery.setId(userId.toString());
            UserLocation userLocation = esTemplate.queryForObject(getQuery, UserLocation.class);
            if (ObjectUtil.isEmpty(userLocation)) {
                UserLocation location = new UserLocation();
                location.setUserId(userId);
                location.setLocation(new GeoPoint(latitude, longitude));
                location.setAddress(address);
                location.setCreated(System.currentTimeMillis());
                location.setUpdated(location.getCreated());
                location.setLastUpdated(location.getCreated());

                // 为空 说明之前没有存储过位置信息  执行新增
                String insertIndex = esTemplate.index(new IndexQueryBuilder()
                        .withObject(location)
                        .build());
                // 新增成功
                return insertIndex != null;
            }
            // 执行更新
            UpdateQuery updateQuery = new UpdateQuery();
            // 更新哪个索引
            updateQuery.setClazz(UserLocation.class);
            // 更新索引中的哪个 记录
            updateQuery.setId(userId.toString());
            // 更新的内容
            UpdateRequest updateRequest = new UpdateRequest();
            // 如果使用的是对象 会出现属性覆盖
            Map mm = new HashMap();
            mm.put("location", new GeoPoint(latitude, longitude));
            mm.put("address", address);
            updateRequest.doc(mm);
            updateQuery.setUpdateRequest(updateRequest);
            UpdateResponse update = esTemplate.update(updateQuery);
            return update.getResult().getOp() >= 1;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 根据用户的id 查询用户的位置信息
     *
     * @param userId
     * @return
     */
    @Override
    public UserLocationVo queryByUserId(Long userId) {
        GetQuery getQuery = new GetQuery();
        getQuery.setId(userId.toString());
        UserLocation userLocation = esTemplate.queryForObject(getQuery, UserLocation.class);
        return UserLocationVo.format(userLocation);
    }

    /**
     * 根据用户的位置信息 搜索周边指定范围内的用户
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @param distance  距离(米)
     * @param counts    要查询多少条
     * @return
     */
    @Override
    public List<UserLocationVo> queryUserFromLocation(Double longitude, Double latitude, Double distance, Integer counts) {
        List<UserLocation> locations = esTemplate.queryForList(new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.geoDistanceQuery("location")
                        .point(latitude, longitude)
                        .distance(distance / 1000, DistanceUnit.KILOMETERS))
                .withSort(SortBuilders.geoDistanceSort("location", latitude, longitude).order(SortOrder.ASC))
                .withPageable(PageRequest.of(0, counts))
                .build(), UserLocation.class);
        return UserLocationVo.formatToList(locations);
    }
}
